package movgen;

import java.util.Arrays;

import state.GameState;


// 
public class Move2 
{
	
	public static final int 				simple	   		       =1;
	public static final int 				kcastle	    	       =2;
	public static final int 				qcastle	    	       =3;
	public static final int 	 			singlePawnMove	       =4;
	public static final int 	 			doublePawnMove	       =5;
	
	public static final int 				simplePromotionQueen   =6;
	public static final int 				captureNoPromotion	   =7;
	public static final int 				epCapture			   =8;
	public static final int 				capturePromotionQueen  =9;

	public static final int TO_SHIFT = 6; // Number of bits to shift to get the to-index
	public static final int PIECE_SHIFT = 12; // To get the piece moving
	public static final int CAPTURE_SHIFT = 16; // To get the capture
	public static final int TYPE_SHIFT = 20; // To the move type
	public static final int ORDERING_SHIFT = 25; // To get the ordering value
	
	
	public static final int SQUARE_MASK = 63; // 6 bits, masks out the rest of the int when it has been shifted so we only get the information we need
	public static final int PIECE_MASK  = 15; // 4 bits
	public static final int TYPE_MASK = 31; // 5 bits
	public static final int ORDERING_CLEAR = 0x1FFFFFF; // = 00000001111111111111111111111111 use with & which clears the ordering value
	/**
	 *  @return int Piece moving
	 */
	public static int pieceMoving(int move)
	{
		return ((move >> PIECE_SHIFT) & PIECE_MASK) ; 
	}
	// END pieceMoving()
	
	/**
	 *  @return int To-index
	 */
	public static int toIndex(int move)
	{
		return ((move >> TO_SHIFT) & SQUARE_MASK);		
	}
	// END toIndex()
	
	/**
	 *  @return int From-index
	 */
	public static int fromIndex(int move)
	{
		return (move & SQUARE_MASK); // Since the from-index is first in the integer it doesn't need to be shifted first		
	}
	// END fromIndex()
	
	/**
	 *  @return int Piece captured
	 */
	public static int capture(int move)
	{
		return ((move >> CAPTURE_SHIFT) & PIECE_MASK) ;		
	}
	// END capture()
	
	/**
	 *  @return int Move type
	 */
	public static int moveType(int move)
	{
		return ((move >> TYPE_SHIFT) & TYPE_MASK);		
	}
	// END moveType()
	
	/**
	 *  @return int Ordering value
	 */
	public static int orderingValue(int move)
	{
		return (move >> ORDERING_SHIFT); // Since the ordering value is last in the integer it doesn't need a mask		
	}
	// END orderingValue()
	
	/**
	 *  Clears the ordering value and sets it to the new number
	 *  
	 *  Important: Ordering value in the move integer cannot be >127
	 *  
	 *  @param move The move to change
	 *  @param value The new ordering value
	 *  @return move The changed moved integer
	 */
	public static int setOrderingValue(int move, int value)
	{
		move = (move & ORDERING_CLEAR); // Clear the ordering value
		return (move | (value << ORDERING_SHIFT)); // Change the ordering value and return the new move integer
	}
	
	//fromType, fromIndex, toIndex, capture, moveType, 0);
	/**
	 *  Creates a move integer from the gives values
	 *  
	 *  @param pieceMoving
	 *  @param fromIndex
	 *  @param toIndex
	 *  @param capture
	 *  @param type
	 *  @param ordering If we want to assign an ordering value at creation time, probably won't be used much for now
	 *  @reutrn move The finished move integer
	 */
	public static int createMove(int pieceMoving, int fromIndex, int toIndex, int capture, int type, int ordering)
	{
		//if (type > 16) System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
		
		int move = 0
		    | fromIndex	// from
			| (toIndex << TO_SHIFT) // to
			| (pieceMoving  << PIECE_SHIFT) // piece moving
			| (capture << CAPTURE_SHIFT) //piece captured 
			| (type << TYPE_SHIFT) // move type
			| (ordering << ORDERING_SHIFT); // ordering value
		return move;
	}
	// END createMove
	

	public static int createMove(String moveS, int fromType, int capture, int moveType)
	//like e2-e4   used in testing only
	{
			String s[] = moveS.split("-");
			String from = s[0];  //like e2
			String to   = s[1];   //like e4
			
			int fromIndex= Util.getIndexFromSquare(from);
			int toIndex= Util.getIndexFromSquare(to);
			
			return createMove(fromType, fromIndex, toIndex, capture, moveType, 0);
	}
	public static void main( String[] args) {
		
		int[] movelist= new int[17];
		
		for (int i=1; i < 17; i++) {
			int min=0, max=50;
			
			int val = min + (int)(Math.random() * ((max - min) + 1));
			
			int move = createMove(3, 4, 5, 6, i, val);
			movelist[i]=move;
			
			System.out.println(toString(move));
			System.out.println(" integer of move " + move);
			int orderingValue = orderingValue(move);
			int type = Move2.moveType(move);
			System.out.println("ordering Value " + orderingValue + " moveType " + type);
		}
		Arrays.sort(movelist);
		for (int i=1; i < 17; i++) {
			int orderingValue = orderingValue(movelist[i]);
			System.out.println("move " + movelist[i] + " order value " + orderingValue);
		}
		int move=0;
		move = setOrderingValue(move, 9);
		System.out.println(toString(move));
		int orderingValue = orderingValue(move);
		System.out.println("ordering Value " + orderingValue);
	}
	
	/**
	 * Gets the file of the given board[] index
	 *
	 * @param   index   array index of position [0-63]
	 * @return  file  of the position ['a'-'h']
	 */
	public static char toFile(int index)
	{
		char file = 'a';
		file += index %  8; // += 0-7
		return file;
	}


	/**
	 * Gets the rank of the given board[] index
	 *
	 * @param   index   array index of position [0-63]
	 * @return  rank of the position [1-8]
	 */
	public static int toRank(int index)
	{
		return (8 - index/8); // 1-8
	}

	
	public static String toString(int move) {
		String s = 
				//"sourceIndex " + sourceIndex + " targetIndex " + targetIndex + "       " +
				//toCoOrdinate( sourceIndex) + 
				//toCoOrdinate( targetIndex );
		  toFile(fromIndex(move)) + "" + toRank(fromIndex(move)) + 
		  toFile(toIndex(move)) + "" + toRank(toIndex(move));
		int type = Move2.moveType(move);
		int pieceMoving = Move2.pieceMoving(move);
		
		if (type == simplePromotionQueen || type == capturePromotionQueen) { //promotion
			return (s + promotionConvert(type, pieceMoving)).trim();
		}
		return s.trim();
	}
	private static  final char promotionConvert(int type, int pieceMoving) {
		
		if (pieceMoving==GameState.WP) {
			switch(type) {
			case Move2.capturePromotionQueen: case Move2.simplePromotionQueen : return 'Q';
			default : return ' ';
		    }
		
		}
		else {
			switch(type) {
			
			case Move2.capturePromotionQueen: case Move2.simplePromotionQueen : return 'q';
			default : return ' ';
		    }
		
		}
	}

}
